#include "dev.h"
#include "cJSON.h"

char fileName[32] = {0};
int fileSize = 0;

void *file_transfer(void *arg)
{ // 创建新套接字供传输配置文件使用
    int sockfd, clientfd;
    int addrlen = sizeof(struct sockaddr);
    struct sockaddr_in addr, clientaddr;
    int nbytes;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket error");
        exit(-1);
    }

    bzero(&addr, addrlen);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(3070);
    int opt = 1;
    if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(const void *)&opt,sizeof(opt)) < 0)
    {
        perror("setsocket error");
        exit(-1);
    }
    if (bind(sockfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind error");
        exit(-1);
    }

    if (listen(sockfd, 5) < 0)
    {
        perror("listen error");
        exit(-1);
    }
    printf("new TCP server created,waiting for connection...\n");
    clientfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen);
    if (clientfd < 0)
    {
        perror("accept error");
        exit(-1);
    }
    printf("connect successful!\n");
    // 开始进行文件传输
    while (1)
    {
        char buf[2048];
        nbytes = recv(clientfd, buf, fileSize, 0);
        printf("%s\n",buf);
        if (nbytes < 0)
        {
            perror("recv error");
            exit(-1);
        }
        else if (nbytes > 0)
        {
            char filePath[32] = {0};
            int len = sprintf(filePath,"./%s",fileName);
            if (len < 0)
            {
                perror("sprintf error");
                exit(-1);
            }
            FILE *nodefp = fopen(filePath, "w+");
            if (nodefp == NULL)
            {
                perror("fopen error");
                exit(-1);
            }
            fputs(buf,nodefp);
            fflush(nodefp);
        }
        else
        {
            printf("File transfer ended.\n");
            break;
        }
    }
    close(sockfd);
    close(clientfd);
    pthread_exit(NULL);
}

int main(int argc, char const *argv[])
{
    // 创建udp套接字
    int udpsocke;
    udpsocke = socket(AF_INET, SOCK_DGRAM, 0);
    if (udpsocke < 0)
    {
        perror("socket error");
        return -1;
    }
    // 绑定IP和PORT
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(3069);
    addr.sin_addr.s_addr = INADDR_ANY;
    int addrlen = sizeof(addr);
    //设置端口重用
    int udpopt = 1;
    if(setsockopt(udpsocke,SOL_SOCKET,SO_REUSEADDR,(const void *)&udpopt,sizeof(udpopt)) < 0)
    {
        perror("setsocket error");
        return -1;
    }
    if (bind(udpsocke, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind err");
        return -1;
    }
    // 接收设备搜索包
    ssize_t len;
    char buf[N] = {0};
    struct sockaddr_in cliaddr;
    while (1)
    {
        bzero(buf, N);
        printf("wait to recv search pack...\n");
        len = recvfrom(udpsocke, buf, N, 0, (struct sockaddr *)&cliaddr, &addrlen);
        if (len == -1)
        {
            perror("recv error");
            return -1;
        }
        if (strcmp(buf, "7355608") == 0)
        {
            printf("recv search pack successful!\n");
            break;
        }
    }
    // 接收成功回复确认包
    sendto(udpsocke, "7355608yes", 11, 0, (struct sockaddr *)&cliaddr, addrlen);
    printf("send reply pack successful!\n");
    close(udpsocke);
    // 创建tcp套接字，转换为tcp服务器
    int tcpsocket = socket(AF_INET, SOCK_STREAM, 0);
    if (tcpsocket < 0)
    {
        perror("socket error");
        return -1;
    }
    int tcpopt = 1;
    if(setsockopt(tcpsocket,SOL_SOCKET,SO_REUSEADDR,(const void *)&tcpopt,sizeof(tcpopt)) < 0)
    {
        perror("setsocket error");
        return -1;
    }
    if (bind(tcpsocket, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind error");
        return -1;
    }
    if (listen(tcpsocket, 5) < 0)
    {
        perror("listen error");
        return -1;
    }
    printf("TCP server already create,Waiting for connection...\n");
    int acceptfd;
    acceptfd = accept(tcpsocket, (struct sockaddr *)&cliaddr, &addrlen);
    if (acceptfd < 0)
    {
        perror("accept error");
        return -1;
    }
    printf("client connected,ip:%s:%d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
    // 等待接收客户端请求包
    pthread_t tid;
    while (1)
    {
        printf("waiting for recv respond...\n");
        memset(buf, 0, N);
        int ret = recv(acceptfd, buf, N, 0);
        if (ret <= 0)
        {
            perror("recv error or client exit");
        }
        // 解析请求包json
        cJSON *root = cJSON_Parse(buf);
        if (NULL == root || strncmp(buf, "{", 1))
        {
            perror("parse error");
            return -1;
        }
        // 解析请求类型
        cJSON *type = cJSON_GetObjectItem(root, "type");
        // 获取服务器参数
        if (type->valueint == 1)
        {
            FILE *nodefp = fopen("./node.json", "r+");
            if (nodefp == NULL)
            {
                memset(buf, 0, N);
                strcpy(buf, "{\"type\":1,\"result\":0,\"up_config\":true}");
                send(acceptfd, buf, N, 0);
            }
            else
            {
                memset(buf, 0, N);
                FILE *upfd = fopen("./up_config.json", "r+");
                fread(buf,1,1024,upfd);
                send(acceptfd, buf, N, 0);
            }
        }
        // 创建子线程接收配置文件
        else if (type->valueint == 2)
        {
            cJSON *data = cJSON_GetObjectItem(root,"data");
            cJSON *flag = cJSON_GetObjectItem(data, "flag");
            if (!strcmp(flag->valuestring,"start"))
            {
                strcpy(fileName,cJSON_GetObjectItem(data,"file_name")->valuestring);
                fileSize = cJSON_GetObjectItem(data,"file_len")->valueint;
                pthread_create(&tid, NULL, file_transfer, NULL);
                memset(buf, 0, N);
                strcpy(buf, "{\"type\":2,\"data\":{\"flag\":\"start\"}}");
                send(acceptfd, buf, N, 0);
            }
            else if (!strcmp(flag->valuestring,"stop"))
            {
                pthread_join(tid, NULL);
                memset(buf, 0, N);
                strcpy(buf, "{\"type\":2,\"data\":{\"flag\":\"stop\"}}");
                send(acceptfd, buf, N, 0);                
            }
            
        }
        // 心跳包检测
        else if (type->valueint == 3)
        {
            memset(buf, 0, N);
            strcpy(buf, "{\"type\": 3,\"result\": 0}");
            send(acceptfd, buf, N, 0);
        }
        sleep(1);
        cJSON_Delete(root);
    }
    return 0;
}
